Skip to main content
Glama

Example Next.js MCP Server

by mat-hiretalk
route.ts6.05 kB
import { createMcpHandler } from "@vercel/mcp-adapter"; import { z } from "zod"; const MOTION_API_KEY = process.env.MOTION_API_KEY; async function fetchMotion(endpoint: string, options: RequestInit = {}) { const res = await fetch(`https://api.usemotion.com/v1/${endpoint}`, { ...options, headers: { "Content-Type": "application/json", "X-API-Key": MOTION_API_KEY!, ...(options.headers || {}), }, }); if (!res.ok) throw new Error(`Motion API error: ${res.statusText}`); return res.json(); } const handler = createMcpHandler( async (server) => { server.tool( "echo", "description", { message: z.string(), }, async ({ message }) => ({ content: [{ type: "text", text: `Tool echo: ${message}` }], }) ); // Get Tasks server.tool( "getTasks", "Get a list of tasks from Motion", {}, async () => { const tasks = await fetchMotion("tasks"); return { content: [{ type: "text", text: JSON.stringify(tasks, null, 2) }], }; } ); // Update Task server.tool( "updateTask", "Update a task in Motion", { taskId: z.string(), updates: z.object({ name: z.string().optional(), description: z.string().optional(), status: z.string().optional(), project: z.string().optional(), workspace: z.string().optional(), deadline: z.string().optional(), startDate: z.string().optional(), duration: z.number().optional(), // Add more fields as needed }), }, async ({ taskId, updates }) => { const updated = await fetchMotion(`tasks/${taskId}`, { method: "PATCH", body: JSON.stringify(updates), }); return { content: [{ type: "text", text: JSON.stringify(updated, null, 2) }], }; } ); // Create Task server.tool( "createTask", "Create a new task in Motion", { name: z.string(), description: z.string().optional(), status: z.string().optional(), project: z.string().optional(), workspace: z.string().optional(), deadline: z.string().optional(), startDate: z.string().optional(), duration: z.number().optional(), // Add more fields as needed }, async ({ name, description, status, project, workspace, deadline, startDate, duration }) => { const created = await fetchMotion("tasks", { method: "POST", body: JSON.stringify({ name, description, status, project, workspace, deadline, startDate, duration }), }); return { content: [{ type: "text", text: JSON.stringify(created, null, 2) }], }; } ); // Delete Task server.tool( "deleteTask", "Delete a task in Motion", { taskId: z.string(), }, async ({ taskId }) => { const deleted = await fetchMotion(`tasks/${taskId}`, { method: "DELETE", }); return { content: [{ type: "text", text: JSON.stringify(deleted, null, 2) }], }; } ); // Create Recurring Task server.tool( "createRecurringTask", "Create a new recurring task in Motion", { name: z.string(), description: z.string().optional(), status: z.string().optional(), project: z.string().optional(), workspace: z.string().optional(), cadence: z.string(), // e.g. 'daily', 'weekly', 'monthly', etc. startDate: z.string().optional(), endDate: z.string().optional(), // Add more fields as needed }, async ({ name, description, status, project, workspace, cadence, startDate, endDate }) => { const created = await fetchMotion("recurring-tasks", { method: "POST", body: JSON.stringify({ name, description, status, project, workspace, cadence, startDate, endDate }), }); return { content: [{ type: "text", text: JSON.stringify(created, null, 2) }], }; } ); // List Recurring Tasks server.tool( "listRecurringTasks", "List recurring tasks in Motion", { workspaceId: z.string().optional(), }, async ({ workspaceId }) => { const endpoint = workspaceId ? `recurring-tasks?workspaceId=${workspaceId}` : "recurring-tasks"; const tasks = await fetchMotion(endpoint); return { content: [{ type: "text", text: JSON.stringify(tasks, null, 2) }], }; } ); // Delete Recurring Task server.tool( "deleteRecurringTask", "Delete a recurring task in Motion", { recurringTaskId: z.string(), }, async ({ recurringTaskId }) => { const deleted = await fetchMotion(`recurring-tasks/${recurringTaskId}`, { method: "DELETE", }); return { content: [{ type: "text", text: JSON.stringify(deleted, null, 2) }], }; } ); }, { capabilities: { tools: { echo: { description: "Echo a message", }, getTasks: { description: "Get a list of tasks from Motion", }, updateTask: { description: "Update a task in Motion", }, createTask: { description: "Create a new task in Motion", }, deleteTask: { description: "Delete a task in Motion", }, createRecurringTask: { description: "Create a new recurring task in Motion", }, listRecurringTasks: { description: "List recurring tasks in Motion", }, deleteRecurringTask: { description: "Delete a recurring task in Motion", }, }, }, }, { basePath: "", verboseLogs: true, maxDuration: 60, } ); export { handler as GET, handler as POST, handler as DELETE };

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/mat-hiretalk/mcp-assistant'

If you have feedback or need assistance with the MCP directory API, please join our Discord server